package com.maomao.admin.service.system.impl;

import com.maomao.admin.common.constant.UserConstants;

import com.maomao.admin.common.exception.ServiceException;
import com.maomao.admin.common.utils.SecurityUtils;
import com.maomao.admin.common.utils.StringUtils;
import com.maomao.admin.common.utils.spring.SpringUtils;
import com.maomao.admin.domain.core.vo.TableDataInfo;
import com.maomao.admin.domain.system.entry.*;
import com.maomao.admin.model.annotation.DataScope;
import com.maomao.admin.persistence.repository.SysRoleDeptRepository;
import com.maomao.admin.persistence.repository.SysRoleMenuRepository;
import com.maomao.admin.persistence.repository.SysRoleRepository;
import com.maomao.admin.persistence.repository.SysUserRoleRepository;
import com.maomao.admin.service.system.AbstractPageService;
import com.maomao.admin.service.system.ISysRoleService;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;

/**
 * 角色 业务层处理
 *
 * @author mao.kaiyin
 */
@Service
@Slf4j
public class SysRoleServiceImpl extends AbstractPageService implements ISysRoleService {


    @Resource
    private JPAQueryFactory queryFactory;

    @Autowired
    private SysRoleRepository roleRepository;

    @Autowired
    private SysRoleMenuRepository roleMenuRepository;

    @Autowired
    private SysRoleDeptRepository roleDeptRepository;

    @Autowired
    private SysUserRoleRepository userRoleRepository;

    /**
     * 根据条件分页查询角色数据
     *
     * @param role 角色信息
     * @return 角色数据集合信息
     */
    @Override
    @DataScope(deptAlias = "d")
    public List<SysRole> selectRoleList(SysRole role) {
        JPAQuery<SysRole> listQuery = this.getListQuery(role);
        return listQuery.fetch();
    }


    private JPAQuery<SysRole> getListQuery(SysRole role) {
        JPAQuery<SysRole> sysRoleJPAQuery = queryFactory.selectFrom(QSysRole.sysRole);
        BooleanExpression eq = QSysRole.sysRole.delFlag.eq("0");
        if (role.getRoleId() != null && role.getRoleId() != 0) {
            eq = eq.and(QSysRole.sysRole.roleId.eq(role.getRoleId()));
        }
        log.info("!!!!!================>>>>>{}", role.getRoleName());
        if (StringUtils.isNotBlank(role.getRoleName())) {
            log.info("================>>>>>{}", role.getRoleName());
            eq = eq.and(QSysRole.sysRole.roleName.contains(role.getRoleName()));
        }
        if (StringUtils.isNotBlank(role.getStatus())) {
            eq = eq.and(QSysRole.sysRole.status.contains(role.getStatus()));
        }
        if (StringUtils.isNotBlank(role.getRoleKey())) {
            eq = eq.and(QSysRole.sysRole.roleKey.contains(role.getRoleKey()));
        }
        Map<String, Object> params = role.getParams();
        if (params != null) {
            Object beginTime = params.get("beginTime");
            if (beginTime instanceof Date) {
                eq = eq.and(QSysRole.sysRole.createTime.gt((Date) beginTime));
            }

            Object endTime = params.get("endTime");
            if (endTime instanceof Date) {
                eq = eq.and(QSysRole.sysRole.createTime.lt((Date) endTime));
            }
        }
        sysRoleJPAQuery.where(eq);
        return sysRoleJPAQuery;

    }

    @Override
    public TableDataInfo<SysRole> selectRolePage(SysRole role) {
        JPAQuery<SysRole> query = this.getListQuery(role);
        super.startPage(query);
        return new TableDataInfo<>(query.fetch(), query.fetchCount());
    }

    /**
     * 根据用户ID查询角色
     *
     * @param userId 用户ID
     * @return 角色列表
     */
    @Override
    public List<SysRole> selectRolesByUserId(Long userId) {
        List<SysRole> userRoles = queryFactory.selectFrom(QSysRole.sysRole)
                .leftJoin(QSysUserRole.sysUserRole).on(QSysUserRole.sysUserRole.id.roleId.eq(QSysRole.sysRole.roleId))
                .where(QSysUserRole.sysUserRole.id.userId.eq(userId)
                        .and(QSysRole.sysRole.delFlag.eq("0"))).fetch();

        List<SysRole> roles = selectRoleAll();
        for (SysRole role : roles) {
            for (SysRole userRole : userRoles) {
                if (role.getRoleId().longValue() == userRole.getRoleId().longValue()) {
                    role.setFlag(true);
                    break;
                }
            }
        }
        return roles;
    }

    /**
     * 根据用户ID查询权限
     *
     * @param userId 用户ID
     * @return 权限列表
     */
    @Override
    public Set<String> selectRolePermissionByUserId(Long userId) {
        List<String> perms = queryFactory.select(QSysRole.sysRole.roleKey).from(QSysRole.sysRole)
                .leftJoin(QSysUserRole.sysUserRole).on(QSysUserRole.sysUserRole.id.roleId.eq(QSysRole.sysRole.roleId))
                .where(QSysUserRole.sysUserRole.id.userId.eq(userId)
                        .and(QSysRole.sysRole.delFlag.eq("0"))).fetch();
        Set<String> permsSet = new HashSet<>();
        for (String perm : perms) {
            if (StringUtils.isNotNull(perm)) {
                permsSet.addAll(Arrays.asList(perm.trim().split(",")));
            }
        }
        return permsSet;
    }

    /**
     * 查询所有角色
     *
     * @return 角色列表
     */
    @Override
    public List<SysRole> selectRoleAll() {
        return SpringUtils.getAopProxy(this).selectRoleList(new SysRole());
    }

    /**
     * 根据用户ID获取角色选择框列表
     *
     * @param userId 用户ID
     * @return 选中角色ID列表
     */
    @Override
    public List<Long> selectRoleListByUserId(Long userId) {
        return queryFactory.select(QSysRole.sysRole.roleId).from(QSysRole.sysRole)
                .leftJoin(QSysUserRole.sysUserRole).on(QSysUserRole.sysUserRole.id.roleId.eq(QSysRole.sysRole.roleId))
                .where(QSysUserRole.sysUserRole.id.userId.eq(userId)
                        .and(QSysRole.sysRole.delFlag.eq("0"))).fetch();
    }

    /**
     * 通过角色ID查询角色
     *
     * @param roleId 角色ID
     * @return 角色对象信息
     */
    @Override
    public SysRole selectRoleById(Long roleId) {
        Optional<SysRole> byId = roleRepository.findById(roleId);
        return byId.orElse(null);
    }

    /**
     * 校验角色名称是否唯一
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    public String checkRoleNameUnique(SysRole role) {
        return this.checkUnique(role, role.getRoleKey(), roleRepository::findByRoleName);
    }

    /**
     * 校验角色权限是否唯一
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    public String checkRoleKeyUnique(SysRole role) {
        return this.checkUnique(role, role.getRoleKey(), roleRepository::findByRoleKey);
    }

    public String checkUnique(SysRole role, String val, Function<String, List<SysRole>> function) {
        Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
        List<SysRole> list = function.apply(val);
        if (list.size() > 1) {
            return UserConstants.NOT_UNIQUE;
        }
        if (list.size() < 1) {
            return UserConstants.UNIQUE;
        }
        SysRole info = list.get(0);
        if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验角色是否允许操作
     *
     * @param role 角色信息
     */
    @Override
    public void checkRoleAllowed(SysRole role) {
        if (StringUtils.isNotNull(role.getRoleId()) && role.isAdmin()) {
            throw new ServiceException("不允许操作超级管理员角色");
        }
    }

    /**
     * 校验角色是否有数据权限
     *
     * @param roleId 角色id
     */
    @Override
    public void checkRoleDataScope(Long roleId) {
        if (!SysUser.isAdmin(SecurityUtils.getUserId())) {
            SysRole role = new SysRole();
            role.setRoleId(roleId);
            List<SysRole> roles = SpringUtils.getAopProxy(this).selectRoleList(role);
            if (StringUtils.isEmpty(roles)) {
                throw new ServiceException("没有权限访问角色数据！");
            }
        }
    }

    /**
     * 通过角色ID查询角色使用数量
     *
     * @param roleId 角色ID
     * @return 结果
     */
    @Override
    public int countUserRoleByRoleId(Long roleId) {
        long cnt = queryFactory.selectFrom(QSysUserRole.sysUserRole).where(QSysUserRole.sysUserRole.id.roleId.eq(roleId)).fetchCount();
        return (int) cnt;
    }

    /**
     * 新增保存角色信息
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    @Transactional
    public int insertRole(SysRole role) {
        // 新增角色信息
        roleRepository.save(role);
//        roleMapper.insertRole(role);
        return insertRoleMenu(role);
    }

    /**
     * 修改保存角色信息
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    @Transactional
    public int updateRole(SysRole role) {
        // 修改角色信息
        roleRepository.save(role);
//        roleMapper.updateRole(role);
        // 删除角色与菜单关联
        RoleMenuPk id = new RoleMenuPk();
        id.setRoleId(role.getRoleId());
        roleMenuRepository.deleteById(id);
//        roleMenuMapper.deleteRoleMenuByRoleId();
        return insertRoleMenu(role);
    }

    /**
     * 修改角色状态
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    public int updateRoleStatus(SysRole role) {
        roleRepository.save(role);
//        return roleMapper.updateRole(role);
        return 0;
    }

    /**
     * 修改数据权限信息
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    @Transactional
    public int authDataScope(SysRole role) {

        // 修改角色信息
//        roleMapper.updateRole(role);
        roleRepository.save(role);
        // 删除角色与部门关联

        RoleDeptPk id = new RoleDeptPk();
        id.setRoleId(role.getRoleId());
        roleDeptRepository.deleteById(id);

//        roleDeptMapper.deleteRoleDeptByRoleId(role.getRoleId());
        // 新增角色和部门信息（数据权限）
        return insertRoleDept(role);
    }


    /**
     * 新增角色菜单信息
     *
     * @param role 角色对象
     */
    public int insertRoleMenu(SysRole role) {
        // 新增用户与角色管理
        List<SysRoleMenu> list = new ArrayList<SysRoleMenu>();
        for (Long menuId : role.getMenuIds()) {
            SysRoleMenu rm = new SysRoleMenu();
            RoleMenuPk id = new RoleMenuPk();
            id.setRoleId(role.getRoleId());
            id.setMenuId(menuId);
            rm.setId(id);
            list.add(rm);
        }
        if (list.size() > 0) {
            roleMenuRepository.saveAll(list);
        }
        return list.size();
    }

    /**
     * 新增角色部门信息(数据权限)
     *
     * @param role 角色对象
     */
    public int insertRoleDept(SysRole role) {
//        int rows = 1;
        // 新增角色与部门（数据权限）管理
        List<SysRoleDept> list = new ArrayList<SysRoleDept>();
        for (Long deptId : role.getDeptIds()) {

            SysRoleDept rd = new SysRoleDept();
            RoleDeptPk id = new RoleDeptPk();
            id.setRoleId(role.getRoleId());
            id.setDeptId(deptId);
            rd.setId(id);

            list.add(rd);
        }
        if (list.size() > 0) {
            roleDeptRepository.saveAll(list);
//            rows = roleDeptMapper.batchRoleDept(list);
        }
        return list.size();
    }

    /**
     * 通过角色ID删除角色
     *
     * @param roleId 角色ID
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteRoleById(Long roleId) {
        // 删除角色与菜单关联
        RoleMenuPk id = new RoleMenuPk();
        id.setRoleId(roleId);
        roleMenuRepository.deleteById(id);
//        roleMenuMapper.deleteRoleMenuByRoleId(roleId);
        // 删除角色与部门关联
//        roleDeptMapper.deleteRoleDeptByRoleId(roleId);
        RoleDeptPk pk = new RoleDeptPk();
        pk.setRoleId(roleId);
        roleDeptRepository.deleteById(pk);
        roleRepository.deleteById(roleId);
        return 1;
    }

    /**
     * 批量删除角色信息
     *
     * @param roleIds 需要删除的角色ID
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteRoleByIds(Long[] roleIds) {
        for (Long roleId : roleIds) {
            checkRoleAllowed(new SysRole(roleId));
            checkRoleDataScope(roleId);
            SysRole role = selectRoleById(roleId);
            if (countUserRoleByRoleId(roleId) > 0) {
                throw new ServiceException(String.format("%1$s已分配,不能删除", role.getRoleName()));
            }
        }
        // 删除角色与菜单关联
        for (Long roleId : roleIds) {
            RoleMenuPk id = new RoleMenuPk();
            id.setRoleId(roleId);
            roleMenuRepository.deleteById(id);
            RoleDeptPk pk = new RoleDeptPk();
            pk.setRoleId(roleId);
            roleDeptRepository.deleteById(pk);
            roleRepository.deleteById(roleId);
        }

//        roleMenuMapper.deleteRoleMenu(roleIds);
        // 删除角色与部门关联
//        roleDeptMapper.deleteRoleDept(roleIds);
//        return roleMapper.deleteRoleByIds(roleIds);
        return roleIds.length;
    }


    /**
     * 取消授权用户角色
     *
     * @param userRole 用户和角色关联信息
     * @return 结果
     */
    @Override
    public int deleteAuthUser(SysUserRole userRole) {
        userRoleRepository.delete(userRole);
//        userRoleMapper.deleteUserRoleInfo(userRole);
        return 0;
    }

    /**
     * 批量取消授权用户角色
     *
     * @param roleId  角色ID
     * @param userIds 需要取消授权的用户数据ID
     * @return 结果
     */
    @Override
    public int deleteAuthUsers(Long roleId, Long[] userIds) {
        for (Long userId : userIds) {
            UserRolePk id = new UserRolePk();
            id.setRoleId(roleId);
            id.setUserId(userId);
            userRoleRepository.deleteById(id);
        }

//        return userRoleMapper.deleteUserRoleInfos(roleId, userIds);
        return 1;
    }

    /**
     * 批量选择授权用户角色
     *
     * @param roleId  角色ID
     * @param userIds 需要授权的用户数据ID
     * @return 结果
     */
    @Override
    public int insertAuthUsers(Long roleId, Long[] userIds) {
        // 新增用户与角色管理
        List<SysUserRole> list = new ArrayList<SysUserRole>();
        for (Long userId : userIds) {
            SysUserRole ur = new SysUserRole();
            UserRolePk id = new UserRolePk();
            id.setUserId(userId);
            id.setRoleId(roleId);
            ur.setId(id);
            list.add(ur);
        }
        userRoleRepository.saveAll(list);
        return list.size();
    }
}
